<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            padding-bottom: 800px;
        }
        .box{
            border: 1px solid black;
            padding: 20px;
        }
    </style>
</head>
<body>
    <div id="app" class="box">
        <h4>父组件</h4>
        <p>msg:{{ msg }}</p>
        <comp-one v-bind:setmsg="setMsg" v-on:sendmsg="setMsg"></comp-one>
    </div>

    <script type="text/x-template" id="compOne">
        <div class="box">
            <h4>子组件</h4>
            <p>msg:{{ msg }}</p>
            <input type="text" v-model="msg">
            <input type="button" value="执行setMsg" @click="doSetMsg()">
            <input type="button" value="执行自定义事件sendmsg" @click="doSendMsg()">

        </div>
    </script>

    <script type="module"> 
        /*
        子向父传递数据：通过在父组件中定义回调方法接收形参，并通过子组件标签将方法传递给子组件，
                       子组件通过执行方法传入实参，完成子向父的数据传递
                       ==> 回调属性绑定+回调触发

        实际项目中基本都是使用事件替换回调的=> 事件绑定+事件触发
                【html的代码习惯，方法一般只会出现在事件绑定;为后续定义组件v-model预留操作方案】
            + 事件绑定 : 子组件标签上以 v-on 指令绑定父组件的方法
            + 事件触发 : 子组件通过 $emit 调用被拦截的事件，并传递数据
        
        传递过程:
            为保证语法的扩展，在子组件标签上以v-on的方式完成自定义事件的绑定，并为其提供定义于父组件的方法；
                            vue在解析组件时，这个自定义事件会被传递给子组件的根元素进行事件绑定，为方便vue
                            调用，vue在$attrs完成以on开头标准事件名记录，开发者可以通过emits属性完成事件拦截，
                            在需要调用时，通过实例方$emit进行触发，并记录回溯日志
        */
    
        import { createApp } from "../../assets/vue3/vue.esm-browser.js";
        const app = createApp({
            data(){
                return {
                    msg:"默认值"
                }
            },
            methods: {
                setMsg(v) {
                    console.log("父组件的setMsg方法:",v)
                    this.msg = v;
                }
            },
        })
        app.component("CompOne",{
            template:"#compOne",
            emits:["sendmsg"],
            data() {
                return {
                    msg: "子组件数据msg"
                }
            },
            methods: {
                doSetMsg() {
                    console.log( this.$attrs.setmsg );
                    this.$attrs.setmsg(this.msg);
                },
                doSendMsg(){
                    // this.$attrs.onSendmsg(this.msg);
                    // this.sendmsg(this.msg);
                    // 框架开发时，父向子数据传递一般都需要保持可回溯性【单向数据流】
                    //            需要在调试工具中记录下相关传递日志=>$emit实例方法就是在触发事件时产生日志
                    this.$emit("sendmsg",this.msg)
                }
            },
        })
        
        app.mount("#app")
    </script>
</body>
</html>